#include "../include/config.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

namespace shiosylar
{

// 全局日志类，名称为'system'
static shiosylar::Logger::ptr g_logger = LOG_NAME("system");

// 遍历一个YAML::Node，将其包含所有的map元素都加载到list中
static void ListAllMember(const std::string& prefix,
                            const YAML::Node& node,
                            std::list<std::pair<std::string, const YAML::Node> >& output)
{
    if(prefix.find_first_not_of("abcdefghikjlmnopqrstuvwxyz._012345678")
            != std::string::npos)
    {
        LOG_ERROR(g_logger) << "Config invalid name: " << prefix << " : " << node;
        return;
    }
    output.push_back(std::make_pair(prefix, node));
    if(node.IsMap())
    {
        for(auto it = node.begin(); it != node.end(); ++it)
        {
            ListAllMember(prefix.empty() ? it->first.Scalar()
            : prefix + "." + it->first.Scalar(), it->second, output);
        }
    }
}

// 传入配置名在容器中进行查找，返回配置类基类的指针，未找到返回空指针
ConfigVarBase::ptr Config::LookupBase(const std::string& name)
{
    RWMutexType::ReadLock lock(GetMutex());
    auto it = GetDatas().find(name);
    return it == GetDatas().end() ? nullptr : it->second;
}

// 从yaml文件中加载配置到当前环境
void Config::LoadFromYaml(const YAML::Node& root)
{
    std::list<std::pair<std::string, const YAML::Node> > all_nodes;
    ListAllMember("", root, all_nodes);

    for(auto& i : all_nodes)
    {
        std::string key = i.first;
        if(key.empty())
            continue;
        std::transform(key.begin(), key.end(), key.begin(), ::tolower);
        ConfigVarBase::ptr var = LookupBase(key);

        if(var)
        {
            if(i.second.IsScalar()) 
                var->fromString(i.second.Scalar());
            else
            {
                std::stringstream ss;
                ss << i.second;
                var->fromString(ss.str());
            }
        }
    }
}

// static std::map<std::string, uint64_t> s_file2modifytime;
// static sylar::Mutex s_mutex;

// void Config::LoadFromConfDir(const std::string& path, bool force)
// {
//     std::string absoulte_path = sylar::EnvMgr::GetInstance()->getAbsolutePath(path);
//     std::vector<std::string> files;
//     FSUtil::ListAllFile(files, absoulte_path, ".yml");
//     for(auto& i : files)
//     {
//         {
//             struct stat st;
//             lstat(i.c_str(), &st);
//             sylar::Mutex::Lock lock(s_mutex);
//             if(!force && s_file2modifytime[i] == (uint64_t)st.st_mtime) {
//                 continue;
//             }
//             s_file2modifytime[i] = st.st_mtime;
//         }
//         try
//         {
//             YAML::Node root = YAML::LoadFile(i);
//             LoadFromYaml(root);
//             SYLAR_LOG_INFO(g_logger) << "LoadConfFile file="
//                 << i << " ok";
//         }
//         catch (...)
//         {
//             SYLAR_LOG_ERROR(g_logger) << "LoadConfFile file="
//                 << i << " failed";
//         }
//     }
// }

void Config::Visit(std::function<void(ConfigVarBase::ptr)> cb)
{
    RWMutexType::ReadLock lock(GetMutex());
    ConfigVarMap& m = GetDatas();
    for(auto it = m.begin(); it != m.end(); ++it)
        cb(it->second);
}


} //namespace shiosylar end